/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.orogeny.buildEnvironments;

import com.softwarecraftsmen.orogeny.filing.AbsolutePath;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static java.lang.String.format;
import java.util.Calendar;
import java.util.GregorianCalendar;
import static java.util.Locale.UK;
import static java.util.TimeZone.getTimeZone;

/**
 * BuildDateTime has three purposes envisaged:-
 * (1) To be used to name folders and files, eg output folders, JARs, etc
 * (2) To be used as a build label or version, or part of a build label
 * (3) To used to time stamp directories and folders (not yet supported)
 * All formats output a leading zero to support these aims
 */
// TODO: Add support for HTTP header formats
public class SimpleBuildDateTime implements BuildDateTime
{
	@NotNull
	public static final String NoSeparator = "";

	@NotNull
	public static final String ColonSeparator = ":";

	@NotNull
	public static final String SlashSeparator = "/";

	@NotNull
	public static final String HyphenSeparator = "-";

	@NotNull
	public static final String DotSeparator = ".";

	@NotNull
	public static final String SpaceSeparator = " ";

	private final Calendar dateTime;

	public SimpleBuildDateTime(final long currentTimeInMilliseconds)
	{
		dateTime = new GregorianCalendar(getTimeZone("UTC"), UK)
		{{
			setTimeInMillis(currentTimeInMilliseconds);
		}};
	}

	@NotNull
	public String iso8601Date()
	{
		return format(UK, "%1$tF", dateTime);
	}

	@NotNull
	public String dailyBuildLabel()
	{
		return yearMonthDay(DotSeparator);
	}

	/**
	 *
	 * @param variant This can be an increasing number (1, 2, 3, ...) through the day, the subversion revision number, or a string (eg "UNKNOWN")
	 * @return A string suitable to use as a build label in file names, formatted as yyyy.mm.dd.variant with leading zeros where necessary
	 */
	@NotNull
	public String interDayBuildLabel(final @NotNull String variant)
	{
		return format(UK, "%1$s%2$s%3$s", yearMonthDay(DotSeparator), DotSeparator, variant);
	}

	@NotNull
	public String byTheSecondBuildLabel()
	{
		return yearMonthDayHourMinuteSecond(DotSeparator, DotSeparator, DotSeparator);
	}

	@NotNull
	public String year()
	{
		return format(UK, "%1$tY", dateTime);
	}

	@NotNull
	public String yearMonth(final @NotNull String dateSeparator)
	{
		return format(UK, "%1$tY%2$s%1$tm", dateTime, dateSeparator);
	}

	@NotNull
	public String yearMonthDay(final @NotNull String dateSeparator)
	{
		return format(UK, "%1$tY%2$s%1$tm%2$s%1$td", dateTime, dateSeparator);
	}

	@NotNull
	public String hour()
	{
		return format(UK, "%1$tH", dateTime);
	}

	@NotNull
	public String hourMinute(final @NotNull String timeSeparator)
	{
		return format(UK, "%1$tH%2$s%1$tM", dateTime, timeSeparator);
	}

	@NotNull
	public String hourMinuteSecond(final @NotNull String timeSeparator)
	{
		return format(UK, "%1$tH%2$s%1$tM%2$s%1$tS", dateTime, timeSeparator);
	}

	@NotNull
	public String hourMinuteSecondMillisecond(final @NotNull String timeSeparator, final @NotNull String millisecondSeparator)
	{
		return format(UK, "%1$tH%2$s%1$tM%2$s%1$tS%3$s%1$tL", dateTime, timeSeparator, millisecondSeparator);
	}

	@NotNull
	public String yearMonthDayHourMinuteSecond(final @NotNull String dateSeparator, final @NotNull String dateToTimeSeparator, final @NotNull String timeSeparator)
	{
		return format(UK, "%1$s%2$s%3$s", yearMonthDay(dateSeparator), dateToTimeSeparator, hourMinuteSecond(timeSeparator));
	}

	@NotNull
	public String yearMonthDayHourMinuteSecondMillisecond(final @NotNull String dateSeparator, final @NotNull String dateToTimeSeparator, final @NotNull String timeSeparator, final @NotNull String millisecondSeparator)
	{
		return format(UK, "%1$s%2$s%3$s", yearMonthDay(dateSeparator), dateToTimeSeparator, hourMinuteSecondMillisecond(timeSeparator, millisecondSeparator));
	}

	public void touch(final @NotNull AbsolutePath absolutePath)
	{
		absolutePath.dynamicMetaData().setModificationTimeInMillisecondsSince1970(dateTime.getTimeInMillis());
	}

	public boolean equals(final @Nullable Object o)
	{
		if (this == o)
		{
			return true;
		}
		if (o == null || getClass() != o.getClass())
		{
			return false;
		}

		final SimpleBuildDateTime that = (SimpleBuildDateTime) o;
		return dateTime.equals(that.dateTime);
	}

	public int hashCode()
	{
		return dateTime.hashCode();
	}

	@NotNull
	public String toString()
	{
		return format(UK, "%1$tc", dateTime);
	}
}
